-
Notifications
You must be signed in to change notification settings - Fork 96
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Outputing subset messages as received (initial work) #233
Conversation
src/subset.rs
Outdated
if self.decided || self.count_true() < self.netinfo.num_correct() { | ||
return None; | ||
} | ||
// Once all instances of BA have completed, let C ⊂ [1..N] be | ||
// the indexes of each BA that delivered 1. Wait for the output | ||
// v_j for each RBC_j such that j∈C. Finally output ∪ j∈C v_j. | ||
if self.ba_results.len() < self.netinfo.num_nodes() { | ||
return None; | ||
return Some(SubsetOutput::Contribution(proposer_id.clone(), | ||
self.broadcast_results.get(proposer_id).map(|x|x.clone()).expect("internal error: already inserted entry not found"))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rustfmt
won't accept this in Travis. Please check the error message.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vkomenda Fixed
d442643
to
ed73c31
Compare
I made no attempt to avoid unnecessary calls to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Current version: all tests pass
This outputs subset messages as they are received. All tests pass.
9ff45d4
to
dba489a
Compare
Squashed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work! Thanks for taking on this issue, @DemiMarie!
I highlighted a few points that need to be addressed before we can merge it.
src/honey_badger/epoch_state.rs
Outdated
let mut map: BTreeMap<N, Vec<u8>> = Default::default(); | ||
self.keys.insert(k.clone()); | ||
map.insert(k, v); | ||
//step.extend(self.send_decryption_shares(map)?); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I think we should do that here: it's the optimization that will hopefully speed up Honey Badger.
We should probably also change send_decryption_share[s]
to take only one value and get rid of map
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So when I do that, I keep running into:
--- test_dynamic_honey_badger_random_delivery_silent stdout ----
thread 'test_dynamic_honey_badger_random_delivery_silent' panicked at 'no more messages in queue', libcore/option.rs:989:5
note: Run with `RUST_BACKTRACE=1` for a backtrace
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@afck is this a testsuite bug or a bug in my code?
src/subset.rs
Outdated
#[derive(Debug, Clone, PartialEq, Eq)] | ||
pub enum SubsetOutput<N> { | ||
Contribution(N, Vec<u8>), | ||
Done(BTreeMap<N, Vec<u8>>), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason to include the values here again? The user has already received the values so it would suffice to just return the set of accepted node IDs (N
), or even nothing at all.
Since the values can be large, it would be nice to avoid any unnecessary cloning.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. I think we need the set of accepted node IDs (so that we can determine whether we are done), but we don’t need to return it.
tests/subset.rs
Outdated
assert_eq!(inputs[&id], value); | ||
} | ||
match output { | ||
SubsetOutput::Contribution(_, _) => unreachable!(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test probably needs to be updated: The algorithm doesn't make the guarantee that all nodes receive the Contribution
s in the same order. What we need to verify is that:
- Each node outputs the same
Contribution
s, although possibly in a different oder. (No duplicates allowed.) - Each node outputs
Done
after all theContribution
s, and no further outputs afterDone
. - The values in the
Contribution
s are the ones matching the corresponding input (already checked below).
src/subset.rs
Outdated
&mut self, | ||
proposer_id: &N, | ||
result: Option<Vec<u8>>, | ||
) -> Option<SubsetOutput<N>> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe the "true" count check in this method should be moved further down, at least if we now want to output Contribution
s (but not Done
) even before we have num_correct()
instances that returned true
.
In any case, we need to make sure that for each accepted value (where the agreement instance returns true
), we output Contribution
exactly once. Note that this can be triggered by two things:
- An agreement instance outputs
true
and we already have the value—the output of the broadcast instance—for it. - A broadcast instance outputs a value and we already have received the output
true
from the corresponding agreement instance. (Not very likely, but it can happen if our node is lagging.)
This fixes the test suite, while still outputting results early.
There is a testsuite failure in the `dynamic_honey_badger` tests. Is this a testsuite bug?
@afck Test suite still fails. Is there a bug in https://github.com/DemiMarie/hbbft/blob/1b37e14d865e2443857379c7b5d32f237af75a73/tests/network/mod.rs#L91-L116? |
@afck what should I change to fix the test suite? |
@DemiMarie The most recent error is simply a formatting error. Just run |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, we check both rustfmt and Clippy (currently disabled, I think) in CI.
Is it normal that the testsuite seems to run in an infinite loop? Edit: Obviously not ― can someone help debug the root cause? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At a glance I couldn't spot the reason for the failing tests so far, but I'm pretty sure something is still wrong with the map
field, since it seems to be read but never written.
If the tests are hanging that probably means that the algorithm currently never terminates but keeps sending messages.
Is it the Honey Badger or the Subset test (or both?) that's hanging?
You can run a single test with the environment variable RUST_LOG=hbbft=debug
to see all the spam very helpful logs. Often it's easier to just use hbbft=info
and add specific info!
logs in the code for debugging to find out what exactly is going on.
2895c55
to
5ea06d0
Compare
Otherwise, we reject all nodes as faulty.
5ea06d0
to
fce3cf7
Compare
All tests pass on my system. |
@afck Thank you for your suggestion; the logs allowed me to figure out the problem quickly |
There is no need to log a quadratic amount of data.
Should I squash? |
We can squash-merge in github. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work! My congratulations on making this work. I have a few minor remarks. Given those are taken into account, I'm for merging this into master. I don't think the change changes censorship resilience. Maybe @afck and @c0gent have different opinion? In any case, the new feature works and it looks good.
the rest of the nodes. Also `panic!` if `Done` is ever not the last value in a series of `SubsetOutput`s.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! Just a few more minor nit-picks.
The tests time out sometimes (we're working on it); I restarted them.
I collected into a BTreeSet, not a Vec. So the order doesn't matter.
…On Wed, Sep 19, 2018, 4:48 PM Vladimir Komendantskiy < ***@***.***> wrote:
***@***.**** requested changes on this pull request.
------------------------------
In tests/subset.rs
<#233 (comment)>:
> // Verify that all instances output the same set.
- let mut expected = None;
+ let observer: BTreeSet<_> = network.observer.outputs().iter().cloned().collect();
.iter().cloned().collect() is equivalent to .to_vec(), I think.
Also you removed observer.sort(). BTW the test appears to pass without
sorting. Maybe for the future (i.e., moving to the new proptest
framework) it would still be better to sort.
------------------------------
In tests/subset.rs
<#233 (comment)>:
> - // The Subset algorithm guarantees that more than two thirds of the proposed elements
- // are in the set.
- assert!(output.len() * 3 > inputs.len() * 2);
- // Verify that the set's elements match the proposed values.
- for (id, value) in output {
- assert_eq!(inputs[&id], value);
+ assert_eq!(outputs.len(), actual.len() + 1);
+
+ // The Subset algorithm guarantees that more than two thirds of the proposed elements
+ // are in the set.
+ assert!(actual.len() * 3 > inputs.len() * 2);
+ for (id, value) in actual {
+ assert_eq!(&inputs[id], value);
+ }
+
+ assert_eq!(outputs.iter().cloned().collect::<BTreeSet<_>>(), observer);
Same observation: .iter().cloned().collect() is equivalent to .to_vec()
and you removed outputs.sort().
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#233 (review)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AGGWB50OVcbMS0yAX-VjLu0EhfL2iKOqks5ucq2wgaJpZM4Wp2j9>
.
|
A |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me! From my side, this can be merged. 👍
(I added one more minor suggestion but that's just a matter of taste.)
@@ -220,7 +227,22 @@ impl<N: NodeIdT + Rand> Subset<N> { | |||
return Ok(step); | |||
} | |||
}; | |||
self.broadcast_results.insert(proposer_id.clone(), value); | |||
|
|||
let val_to_insert = if let Some(true) = self.ba_results.get(proposer_id) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to pattern-match here: This could just be if Some(true) == self.ba_results.get(proposer_id)
.
On the other hand, maybe it should be a match
instead: I'm wondering whether in the Some(false)
case, we should also just insert None
, since we won't need the value anyway—we already know it has been rejected?
Closes #170.
This is still incomplete; in particular, I need to fix up the test suite.